<template>
  <div>
    <!-- 搜索区域 -->
    <van-search v-model="keyword" @input="getSuggestList" placeholder="请输入搜索关键词" shape="round" />
    <!-- 搜索历史区 -->
    <div class="history" v-show="suggestList.length === 0">
      <van-tag class="tag" plain type="primary" v-for="item in historyList" :key="item">{{item}}</van-tag>
    </div>

    <!-- 搜索联想区域 -->
    <div class="sugg-list">
        <div class="sugg-item" v-for="item in suggestList" :key="item" @click="goResult(item)">
          <span v-html="formartStr(item)"></span>
        </div>
    </div>
  </div>
</template>

<script>
/**
 * 1. 输入框输入内容 获取搜索联想关键词列表 显示
 *   1. 双向绑定 获取输入的内容
 *   2. 监听输入框的事件 input事件 回调中调用接口
 *   3. 获取数据列表 渲染列表中
 *
 * 2. 高亮关键词
 *   核心思路: 'abcdA' -> '<span style="color:red;">a</span>bcd<span style="color:red;">A</span>'
 *   核心技术
 *    1. 如何根据keyword生成一个用来替换的正则  new RegExp 全局 g 不区分大小写 i
 *    2. replace('要替换的字符串/正则表达式','替换后的样子/回调函数')
 *    3. 富文本  v-html  {{}} v-text
 *
 *   具体方案: 直接通过一个格式化方法 在template模板的对应位置执行方法进行渲染 不动原始数据
 *
 * 3. 防抖优化操作
 *   背景：在用户输入的行为停止之后一定时间内不再进行输入事件触发 才能发送请求
 *   防抖本质: 把先前事件触发的行为操作清除 只保留最后一次
 *   具体做法： [this]
 *    1. lodash
 *    2. 手动编写防抖
 *
 * 4. 缓存搜索记录
 *   交互:只要我们点击了某个联想关键词进行了搜索跳转 就把这个关键词记录下来
 *   等到用户下一次进来搜索页 直接展示前几次的记录
 *   如何做？
 *    1. 借助ls做缓存
 *    2. 点击事件发生时就往本地存
 *    3. 页面初始化从本地先取一下之前的记录渲染一下
 */

import { suggestListAPI } from '@/api'

// 防抖函数
// 原理: 每次执行回调之前，先把上一次的回调清除掉，再开启一个新的回调
// 核心技术：延时器 setTimeout

function debounce (fn, time) {
  let timer = null
  return function () {
    // 清除上一次的timer
    clearTimeout(timer)
    timer = setTimeout(() => {
      // 1. 问题产生的原因是因为fn内部的this指向的不是组件的实例对象
      // 2. 解决的办法就是强制让fn内部的this指向 变成当前的组件实例对象
      // 3. 这个外层函数的function最终会被debounce执行之后赋值给组件选项methods中的getSuggestList
      // 4. 组件选项methods中的每一个方法内部的this都会被vue框架强制指向组件实例对象
      fn && fn.call(this)
    }, time)
  }
}

export default {
  name: 'search-index',
  data () {
    return {
      keyword: '',
      suggestList: [],
      historyList: JSON.parse(window.localStorage.getItem('history')) || []
    }
  },
  methods: {
    // 用防抖函数改写
    // 现在改写之后 我们input事件实际执行的回调函数是谁？
    // debounce函数执行之后的返回值 返回值也是一个函数
    // function debouce(){ .... return function(){} }
    // 注意: 这里的第一个参数不能写成箭头函数 this -> undefined
    // vue内部会对methods中所有的方法进行this的指向修改 修改到当前的组件实例
    // 但是如果你传递的是一个 箭头函数 箭头函数的this是不可以被修改的 vue框架改不了 this不指向vm
    getSuggestList: debounce(async function () {
      const res = await suggestListAPI({
        q: this.keyword
      })
      this.suggestList = res.data.options
    }, 400),
    formartStr (str) {
      const reg = new RegExp(this.keyword, 'ig')
      return str.replace(reg, (key) => {
        // key: 当前匹配到了哪个字符 key指的就是哪个字符
        // 'abcA' keyword='a'  key a A
        return `<span style="color:red;">${key}</span>`
      })
    },
    goResult (keyword) {
      // 存关键词
      this.historyList.push(keyword)
      // 去重
      const _list = [...new Set(this.historyList)]
      window.localStorage.setItem('history', JSON.stringify(_list))
      this.$router.push({
        path: '/searchResult',
        query: {
          keyword
        }
      })
    }
  }

}
</script>
<style scoped lang="less">
 /*搜索建议列表样式 */
.sugg-list {
  .sugg-item {
    padding: 0 15px;
    border-bottom: 1px solid #f8f8f8;
    font-size: 14px;
    line-height: 50px;
    // 实现省略号的三行代码
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color:rgba(0, 0, 0, 0.65)
  }
}
.history{
  padding:10px 20px;
  .tag{
    margin-right: 6px;
  }
}
</style>
